home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume2 / 3b1-status-line < prev    next >
Encoding:
Internet Message Format  |  1991-08-07  |  30.0 KB

  1. From: scott@zorch.UUCP (Scott Hazen Mueller)
  2. Newsgroups: comp.sources.misc
  3. Subject: v02i004: 3B1 status bar redux
  4. Message-ID: <7078@ncoast.UUCP>
  5. Date: 15 Jan 88 00:28:37 GMT
  6. Approved: allbery@ncoast.UUCP
  7.  
  8. Comp.Sources.Misc: Volume 2, Issue 4
  9. Submitted-By: Scott Hazen Mueller <scott@zorch.uucp>
  10. Archive-Name: 3b1-status-line
  11.  
  12. This is a considerable enhanced (enhacked?) version of the 3B1 status bar
  13. program that I posted to comp.sources.misc around last October.  This version
  14. is not quite so minimal.  In addition to displaying a status line across the
  15. top of the screen, it uses the Suspend and Resume keys to switch to the next
  16. and previous windows; combined with multiple console gettys it gives behavior
  17. rather like that of 80x86-based Unices with virtual consoles.  Also, it maps
  18. a bunch of 'extended-status' functions to the shifted Function keys on the
  19. console keyboard (and a help function to shift-Print).
  20.  
  21. #! /bin/sh
  22. # This is a shell archive, meaning:
  23. # 1. Remove everything above the #! /bin/sh line.
  24. # 2. Save the resulting text in a file.
  25. # 3. Execute the file with /bin/sh (not csh) to create the files:
  26. #    ReadMe
  27. #    Makefile
  28. #    newmgr.c
  29. #    startmgr.c
  30. #    ndir.c
  31. #    ndir.h
  32. # This archive created: Sat Jan  9 21:15:14 1988
  33. export PATH; PATH=/bin:$PATH
  34. if test -f 'ReadMe'
  35. then
  36.        echo shar: will not over-write existing file "'ReadMe'"
  37. else
  38. cat << \SHAR_EOF > 'ReadMe'
  39.  
  40. ReadMe for 9 Jan 1988 version of startmgr and newmgr
  41.  
  42. These two programs implement a replacement for smgr, wmgr and ph.  They don't
  43. do the cron stuff; use cron for that.  They don't do mail, and I don't care,
  44. because I don't use /bin/mail anyway.  Likewise, they know nothing about
  45. calendars or memos.  Additionally, the wmgr function doesn't bring up a menu;
  46. it just switches you between windows.
  47.  
  48. What startmgr does is start newmgr.  It starts it in a window across the
  49. top of the screen, in the places where the Phone Manager, the Status Manager
  50. and the Window Manager live (I don't use the PM either...).  It then returns,
  51. so all you need to do is startmgr.  It probably can be turned into a fairly
  52. general process starter, but I don't have the time, what with all of the
  53. stuff that I've got piled up to look at.
  54.  
  55. Newmgr is just a forever loop that displays some status information to
  56. stdout and peeks at the Suspend, Resume Shift-Print and Shift-Function Keys.
  57. The Shift-Function keys display all sorts of additional status information;
  58. since I use UUCP a lot, four of the keys show UUCP-related information (LCK,
  59. C. and D.  files and all of /usr/spool/uucp) and the other four show process
  60. status, utmp information, the mail directory, and root disk stats.  Feel free
  61. to hack it; I just put up what I could think of that's interesting to me.  Load
  62. averages would be nice, but I couldn't find any obvious hooks in /unix for that.
  63.  
  64. Compiling:  just type make.  Use make install to move the executables to the
  65. default locations.  Modify the Makefile and the #define BARPROG for your site.
  66. I use the ndir stuff (I got it from News, I don't know who did it originally)
  67. to do directory scanning; it should be in the distribution.
  68.  
  69. How to use:  startmgr goes in /etc/daemons and newmgr goes into your
  70. local executable directory (change a #define in startmgr if you don't
  71. use /usr/local).  You've then either got to change /etc/rc (so it doesn't
  72. start smgr,wmgr and ph) or put a script in /etc/daemons to kill them off.
  73. If you don't know about /etc/rc and /etc/daemons, maybe you shouldn't
  74. be doing this... :-)
  75.  
  76. Use the Shift-Print key to display the list of key mappings, once the program
  77. is started.
  78.  
  79. Optionally, you *can* run startmgr by hand; I did for testing.  The only
  80. thing to note here is that your current window winds up being the one
  81. that startmgr creates for the status line; I couldn't find a way to say,
  82. "make the last window the current one."; or at least, one that I could get
  83. to work in 5 minutes...  To get back to your normal window, just use
  84. Suspend/Resume.
  85.  
  86. Known bugs:  Every once in a while, like if you log out *just* as the display
  87. is updating, it gets confused as to what window you're really in.  It has even
  88. been known to display "w-1" (who me, check for errors on a system call?).
  89. Also, the process status feature probably could find a better way to determine
  90. a process's controlling terminal; it has a tendency to come up with things
  91. like /dev/null.
  92.  
  93. Potential bugs:  Pretty much all of the extended-status routines are
  94. implemented without any error-checking...
  95.  
  96. Last note:  this stuff is copyrighted with free redistribution permitted.
  97. I don't really think that this is the sort of thing that needs or warrants
  98. scads of support, so I'm not promising to do so; however, I would like to
  99. see any changes that anyone makes.
  100.  
  101. Comments welcome, as long as they are other than, "What kind of idiot
  102. runs without smgr, wmgr and ph?"
  103.  
  104.      \scott
  105.      9 Jan 1988
  106.  
  107. SHAR_EOF
  108. fi # end of overwriting check
  109. if test -f 'Makefile'
  110. then
  111.        echo shar: will not over-write existing file "'Makefile'"
  112. else
  113. cat << \SHAR_EOF > 'Makefile'
  114. LOCALDIR = /usr/local
  115.  
  116. all: newmgr startmgr
  117.  
  118. startmgr: startmgr.c
  119.     cc -O -s startmgr.c -o startmgr
  120.  
  121. newmgr: newmgr.o ndir.o
  122.     cc -O -s newmgr.o ndir.o -o newmgr
  123.  
  124. install: newmgr startmgr
  125.     mv newmgr LOCALDIR
  126.     mv startmgr /etc/daemons
  127.  
  128. clean:
  129.     rm -f *.o startmgr newmgr
  130. SHAR_EOF
  131. fi # end of overwriting check
  132. if test -f 'newmgr.c'
  133. then
  134.        echo shar: will not over-write existing file "'newmgr.c'"
  135. else
  136. cat << \SHAR_EOF > 'newmgr.c'
  137. /*    newmgr:  Loop forever, printing a status display and checking the
  138.     Suspend, Resume and shifted Function Keys.  Meant to be used on the
  139.     top line of a Unix-PC (7300/3B1) screen that has had the Phone Manager,
  140.     Status Manager and Window Manager disabled.  What it shows:
  141.  
  142.     - Phone line states
  143.         o Idle - completely free line
  144.         o Ansr - computer answering line (getty job)
  145.         o Mach - incoming machine
  146.         o User - incoming user
  147.         o Call - any outbound
  148.     - Boot date and time
  149.     - Current run level
  150.     - Current date and time
  151.     - Number of users
  152.  
  153.     When Suspend is hit, it makes the next window current; Resume
  154.     makes the last window current.
  155.  
  156.     The following functions are mapped to the function keys:
  157.  
  158.     Shift-F1:  process display, similar to 'ps -ef'
  159.     Shift-F2:  utmp display, like 'who'
  160.     Shift-F3:  lists UUCP LCK.. files, if any
  161.     Shift-F4:  directory of /usr/mail
  162.     Shift-F5:  Root filesystem freespace and free inodes
  163.     Shift-F6:  lists UUCP C. files, if any
  164.     Shift-F7:  lists UUCP X. files, if any
  165.     Shift-F8:  directory of /usr/spool/uucp
  166.  
  167.     This is started by startmgr (which should be included in any
  168.     distribution) so that the fork/exec/open code doesn't have to be
  169.     carried around with this program.
  170.  
  171.     The process table stuff is heavily inspired by the 'fuser.c' program
  172.     posted to the Usenet by Michael 'Ford' Ditto.
  173.  
  174.     This software is Copyright (c) 1987 by Scott Hazen Mueller.
  175.  
  176.     Permission is hereby granted to copy, reproduce, redistribute or
  177.     otherwise use this software as long as: there is no monetary
  178.     profit gained specifically from the use or reproduction or this
  179.     software, it is not sold, rented, traded or otherwise marketed, and
  180.     this copyright notice is included prominently in any copy
  181.     made.
  182.  
  183.     The author make no claims as to the fitness or correctness of
  184.     this software for any use whatsoever, and it is provided as is. 
  185.     Any use of this software is at the user's own risk.
  186.  
  187.     (Copyright notice courtesy of News 2.11 :-)
  188.  
  189.     Additionally:  you break it, you bought it.  I've listed the problems
  190.     that I know of in comments in the code; if you come up with fixes, I'd
  191.     like to see them, but I'm not planning on supporting anything.  It's
  192.     "good enough"; that's all that I'm looking for.    */
  193.  
  194. #include    <stdio.h>
  195. #include    <sys/types.h>
  196. #include    <sys/phone.h>
  197. #include    <sys/window.h>
  198. #include    <sys/signal.h>
  199. #include    <sys/filsys.h>
  200. #include    <sys/proc.h>
  201. #include    <sys/user.h>
  202. #include    <sys/syslocal.h>
  203. #include    <sys/tune.h>
  204. #include    <sys/stat.h>
  205. #include    <fcntl.h>
  206. #include    <time.h>
  207. #include    <utmp.h>
  208. #include    <nlist.h>
  209. #include    <pwd.h>
  210. #include    "ndir.h"
  211.  
  212. #define        PHONE1        "ph0"
  213. #define        PHONE2        "ph1"
  214. #define        IDLE        0
  215. #define        ANSR        1
  216. #define        MACH        2
  217. #define        USER        3
  218. #define        CALL        4
  219. #define        BARFORM        "%s1 %s2 | Up Since %s | %s | %s | %d Users | w%d \r"
  220. #define        MACHLEN        15
  221. #define        MAXPATHLEN    255
  222. #define        LOCKDIR        "/usr/spool/uucp/"
  223. #define        MAILDIR        "/usr/mail/"
  224. #define        DEVDIR        "/dev/"
  225. #define        LOCKPREFIX    "LCK.."
  226. #define        COMPREFIX    "C."
  227. #define        UUXPREFIX    "X."
  228. #define        TRUE        (1)
  229. #define        FALSE        (0)
  230. #define        TIMEFORM    "%.2d/%.2d %.2d:%.2d"
  231. #define        TICK        15
  232. #define        WHOSLEEP    15
  233. #define        NOWHERE        0
  234. #define        FORWARD        1
  235. #define        BACKWARD    2
  236. #define        HERE        3
  237. #define        MINWIN        1
  238. #define        MAXWIN        12
  239.  
  240. char    *phstat[5] = { "Idle", "Ansr", "Mach", "User", "Call" };
  241.  
  242. main()
  243. {
  244. int        nusers;
  245. char    curtime[26], boottime[26], rl[12], line[80], *fmttime();
  246. struct    utmp *ut, *getutent();
  247. long    temp;
  248.  
  249. /*    Ignore keyboard interrupt signals.    */
  250.  
  251. signal( SIGINT, SIG_IGN );
  252. signal( SIGQUIT, SIG_IGN );
  253.  
  254. /*    Open up the utmp file and find the boot time; save for display.    */
  255.  
  256. while ( ( ut = getutent() ) != NULL )
  257.     if ( (int) ut->ut_type == BOOT_TIME ) {
  258.         strcpy( boottime, fmttime( localtime( &( ut->ut_time ) ) ) );
  259.         break;
  260.     }
  261. endutent();
  262.  
  263. for (;;) {
  264.  
  265. /*    Scan the utmp file, noting the run level and totting up users.    */
  266.  
  267.     nusers = 0;
  268.     while ( ( ut = getutent() ) != NULL ) {
  269.         switch ( (int) ut->ut_type ) {
  270.             case USER_PROCESS : nusers++; break;
  271.             case RUN_LVL : strcpy( rl, ut->ut_line ); break;
  272.             default : break;
  273.             }
  274.         }
  275.     endutent();
  276.  
  277. /*    Figure out the current time.  Temp is needed 'cause localtime wants
  278.     an address.    */
  279.  
  280.     temp = time( (long *) 0 );
  281.     strcpy( curtime, fmttime( localtime( &temp ) ) );
  282.  
  283. /*    Format and print.  Flush stdout to make it really get printed.    */
  284.  
  285.     sprintf( line, BARFORM, phstat[ phone_stat( PHONE1 ) ],
  286.         phstat[ phone_stat( PHONE2 ) ], boottime, rl, curtime, nusers,
  287.         curwinno() );
  288.     printf( "%s", line );
  289.     fflush( stdout );
  290.  
  291. /*  Take care of the window management stuff; also do some sleeping down
  292.     there.    */
  293.  
  294.     wcheckz();
  295.     }
  296. }
  297.  
  298. char *fmttime( tm )
  299.  
  300. /*    Format a time structure into a string the way *I* want it.    */
  301.  
  302. struct tm *tm;
  303. {
  304. char  abuf[26];
  305.  
  306. sprintf( abuf, TIMEFORM, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min );
  307. return( abuf );
  308. }
  309.  
  310. phone_stat( phone )
  311. char    *phone;
  312.  
  313. /*    Figure out the phone line status.  There are five possible states:
  314.         Idle - completely free line
  315.         Ansr - getty
  316.         Mach - incoming machine
  317.         User - incoming user
  318.         Call - outbound
  319.  
  320.     These five states are defined roughly as follows:
  321.  
  322.         Ansr - utmp -> LOGIN_PROCESS.
  323.         Mach - utmp -> USER_PROCESS; E LCK.
  324.         User - utmp -> USER_PROCESS; ~E LCK.
  325.         Call - utmp -> nothing; E LCK.
  326.         Idle - utmp -> nothing; ~E LCK.
  327.  
  328.     Basically, we decide what we have by a process of elimination.
  329.  
  330.     Known bugs:  This may have problems with HDB UUCP, since I've got no
  331.     way to test against it.  One thing that I am sure of is that since I
  332.     believe that uugetty creates a LCK..device file, this routine will
  333.     consistently mistake users logged in through uugetty for machines
  334.     logged into uucico.    */
  335.  
  336. {
  337. struct utmp    ut_try, *ut, *getutline();
  338. short    utmptype;
  339. char    machine[MACHLEN];
  340.  
  341. /*    Look for the phone line in the utmp file.  getutline() should return
  342.     only LOGIN_PROCESS, USER_PROCESS, or NULL (for failure).  We need to
  343.     save some values before the endutent() call because it clears out the
  344.     static structure pointed to by the return value of getutline().  We
  345.     save the ut_user field because uucico creates a machine LCK file using
  346.     the first six characters of this name.    */
  347.  
  348. strcpy( ut_try.ut_line, phone );
  349. ut = getutline( &ut_try );
  350. utmptype = ut->ut_type;
  351. strcpy( machine, ut->ut_user );
  352.  
  353. /*    AT&T UUCP specifies a maximum length of six characters.  Remove this
  354.     line for less brain-damaged implementations.    */
  355.  
  356. machine[6] = '\0';
  357. endutent();
  358.  
  359. /*    First condition:  was there a utmp entry?    */
  360.  
  361. if ( ut != NULL )
  362.  
  363. /*    There was.  If the type field is LOGIN_PROCESS, we have a getty and can
  364.     return the appropriate value and quit.    */
  365.  
  366.     if ( utmptype == LOGIN_PROCESS )
  367.         return( ANSR );
  368.     else
  369.  
  370. /*    A USER_PROCESS is incoming and can be either a user or a uucico.  An
  371.     incoming uucico has a LCK..machine file, so we check for that.    */
  372.  
  373.         return( locked( machine ) ? MACH : USER );
  374. else
  375.  
  376. /*    There is no utmp entry.  There are only two possibilities here; if there
  377.     is an outgoing call of some sort, there will be a LCK..device file; if
  378.     not, the line is really idle.    */
  379.  
  380.         return( locked( phone ) ? CALL : IDLE );
  381.  
  382. /*    Shouldn't reach here.    */
  383.  
  384. }
  385.  
  386. locked( device )
  387. char    *device;
  388.  
  389. /*    See if a lock file exists.    */
  390.  
  391. {
  392. char    temp[MAXPATHLEN];
  393. int        fd;
  394.  
  395. /*    Make up the full path name.    */
  396.  
  397. strcpy( temp, LOCKDIR );
  398. strcat( temp, LOCKPREFIX );
  399. strcat( temp, device );
  400.  
  401. /*    Attempt to open the lock file.  Assume that if the open fails the lock
  402.     file does not exist.    */
  403.  
  404. fd = open( temp, O_RDONLY );
  405. if ( fd == -1 )
  406.     return( FALSE );
  407. close( fd );
  408. return( TRUE );
  409. }
  410.  
  411. curwinno()
  412.  
  413. /*    Figure out the current window; we need a starting point, after all.
  414.     Known bug:  this sometimes returns the wrong value if it gets into a
  415.     race condition with a terminating/restarting (eg, getty) job.  It also
  416.     doesn't check to see if the ioctl fails.    */
  417.  
  418. {
  419. int        foowin, dummy, temp;
  420.  
  421. foowin = open( "/dev/window", O_RDONLY );
  422. temp = ioctl( foowin, WIOCGCURR, dummy );
  423. close( foowin );
  424. return( temp );
  425. }
  426.  
  427. wcheckz()
  428.  
  429. /*    This is where the code to check for change-window keys lives.  Also,
  430.     sleep for the main program here.  It should return about every TICK
  431.     seconds.    */
  432.  
  433. {
  434. int        tock, newwin, dir;
  435.  
  436. tock = 0;
  437.  
  438. do {
  439. /*    Check for a command key.    */
  440.  
  441.     if ( ( dir = checkey() ) != NOWHERE ) {
  442.  
  443. /*    Determine which window is next and select it.    */
  444.  
  445.         if ( dir != HERE ) {
  446.             newwin = nexwin( curwinno(), dir );
  447.             ioctl( newwin, WIOCSELECT );
  448.             close( newwin );
  449.             }
  450.         tock = TICK;        /*    Kludge to force return and redisplay.    */
  451.         }
  452.     }
  453.  
  454. /*    Return after TICK tocks.    */
  455.  
  456. while ( tock++ < TICK );
  457. }
  458.  
  459. justgoon()
  460.  
  461. /*    Stub routine to "handle" the alarm signal.  Doesn't do a lot.    */
  462.  
  463. {
  464. return;
  465. }
  466.  
  467. checkey()
  468.  
  469. /*    Check and see if one of our keys has been poked.  The only keys this window
  470.     is supposed to respond to all generate three character escape sequences.
  471.     Set and catch an alarm signal to keep from getting hung in the fread();
  472.     this probably could be done more neatly some other way, but...    */
  473.  
  474. {
  475. int        direction, i;
  476. FILE    *fw;
  477. char    key[3];
  478.  
  479. /*    Set the alarm signal.    */
  480.  
  481. signal( SIGALRM, justgoon );
  482. alarm( 1 );
  483. if ( fread( key, 1, 3, stdin ) == 3 ) {
  484.  
  485. /*    Reset the alarm signal to be ignored.    */
  486.  
  487.     signal( SIGALRM, SIG_IGN );
  488.     alarm( 0 );
  489.  
  490. /*    Pick a function.    */
  491.  
  492.     switch ( key[2] ) {
  493.         case 'C' : showprocs(); direction=HERE; break;
  494.         case 'D' : showutmp(); direction=HERE; break;
  495.         case 'E' : showdir( LOCKDIR, LOCKPREFIX ); direction=HERE; break;
  496.         case 'F' : showdir( MAILDIR, "" ); direction=HERE; break;
  497.         case 'G' : showfsys(); direction=HERE; break;
  498.         case 'H' : showdir( LOCKDIR, COMPREFIX ); direction=HERE; break;
  499.         case 'I' : showdir( LOCKDIR, UUXPREFIX ); direction=HERE; break;
  500.         case 'J' : showdir( LOCKDIR, "" ); direction=HERE; break;
  501.         case 'p' : 
  502.         case 'P' : direction = FORWARD; break;
  503.         case 'q' :
  504.         case 'Q' : direction = BACKWARD; break;
  505.         case 'Z' : help(); direction = HERE; break;
  506.         default : direction = NOWHERE; break;
  507.         }
  508.     }
  509.     else
  510.         direction = NOWHERE;
  511.  
  512. /*    Reset the alarm signal to be ignored.    */
  513.  
  514. signal( SIGALRM, SIG_IGN );
  515. alarm( 0 );
  516. return( direction );
  517. }
  518.  
  519. nexwin( winno, dir )
  520. int winno, dir;
  521.  
  522. /*    Decide what should be the next window.  This relies on the fact that
  523.     when you open a window device directly the open call will fail if it has
  524.     not already been opened by someone else; this is how we find the open
  525.     windows.  Invisible windows should have their user-text set to "Invisible"
  526.     if they wish to be ignored.    */
  527.  
  528. {
  529. int        wd;
  530. char    windex[12];
  531. struct    utdata    wintext;
  532.  
  533. /*    Trivial loop; at worst, we'll wind up back where we started.  I suppose
  534.     it's possible to have a system with no windows except those marked as
  535.     "Invisible"; it doesn't seem too useful, though.    */
  536.  
  537. while ( 1 ) {
  538.  
  539. /*    Forward/backward sort-of modulo arithmetic.  Real modulo arithmetic
  540.     starts at zero.    */
  541.  
  542.     winno += ( dir == FORWARD ? 1 : -1 );
  543.     if ( winno > MAXWIN )
  544.         winno = MINWIN;
  545.     else if ( winno < MINWIN )
  546.         winno = MAXWIN;
  547.  
  548. /*    Generate a window name and test for existence.    */
  549.     sprintf( windex, "/dev/w%d", winno );
  550.     if ( ( wd = open( windex, O_RDONLY ) ) != -1 ) {
  551.  
  552. /*    It exists, now look at its user text info.  This is where "Invisible"
  553.     gets skipped.    */
  554.  
  555.         wintext.ut_num = WTXTUSER;
  556.         ioctl( wd, WIOCGETTEXT, &wintext );
  557.         if ( strcmp( wintext.ut_text, "Invisible" ) )
  558.             return( wd );
  559.         else
  560.             close( wd );
  561.         }
  562.     }
  563. }
  564.  
  565. showprocs()
  566.  
  567. /*    Find the process table; run through it, looking up the user areas and
  568.     printing out some data on each one on the fly.  Works like 'ps -ef'
  569.     command.    */
  570.  
  571. {
  572. struct proc    *ppt;
  573. static struct nlist    sym[3] = { { "tuhi", }, { "proc", }, { (char *)0, }, };
  574. struct tunable    tune;
  575. int    mem, kmem;
  576. FILE    *wp;
  577.  
  578. signal( SIGALRM, justgoon );
  579.  
  580. /*    Open up a window; also open the memory devices for reading.    */
  581.  
  582. wp = fopen( "/dev/window", "w" );
  583. mem = open( "/dev/mem", O_RDONLY );
  584. kmem = open( "/dev/kmem", O_RDONLY );
  585.  
  586. /*    Find the tunable parameters, to get the maximum number of processes; and
  587.     the process table.    */
  588.  
  589. nlist( "/unix", sym );
  590. dmemcopy( kmem, (char *)&tune, (long)(sym[0].n_value), (long)sizeof( tune ) );
  591. dmemcopy( kmem, (char *)&ppt, (long)(sym[1].n_value), (long)sizeof( ppt ) );
  592.  
  593. /*    Run through the process table.    */
  594.  
  595. fprintf( wp, "REAL UID EFECT ID  PID   PPID START TIME    TTY  COMMAND\n" );
  596. while ( tune.nproc-- )
  597.     printproc( wp, kmem, mem, ppt++ );
  598.  
  599. /*    Empty the output buffer, sleep to allow it to be read, and close up the
  600.     extra window and return.    */
  601.  
  602. fflush( wp );
  603. sleep( WHOSLEEP );
  604. fclose( wp );
  605. signal( SIGALRM, SIG_IGN );
  606. }
  607.  
  608. showutmp()
  609.  
  610. /*    Run through the utmp file.  Used to give an idea of system activity.    */
  611.  
  612. {
  613. struct    utmp *ut, *getutent();
  614. FILE    *wp;
  615.  
  616. signal( SIGALRM, justgoon );
  617. wp = fopen( "/dev/window", "w" );
  618.  
  619. /*    Go through utmp.  Show login and user processes.    */
  620.  
  621. while ( ( ut = getutent() ) != NULL ) {
  622.     switch ( (int) ut->ut_type ) {
  623.         case USER_PROCESS : 
  624.         case LOGIN_PROCESS : showutent( wp, ut );
  625.         default : break;
  626.         }
  627.     }
  628. endutent();
  629. fprintf( wp, "\n" );
  630. fflush( wp );
  631. sleep( WHOSLEEP );
  632. fclose( wp );
  633. signal( SIGALRM, SIG_IGN );
  634. }
  635.  
  636. showdir( dirname, mask )
  637. char    *dirname, *mask;
  638.  
  639. /*    Display the contents of a directory.  Use 'mask' to specify a file prefix
  640.     string to look for; useful for finding 'LCK..' files.    */
  641.  
  642. {
  643. DIR    *dirp;
  644. struct    directy *dir;
  645. FILE    *wp;
  646. int    mlen;
  647.  
  648. signal( SIGALRM, justgoon );
  649. wp = fopen( "/dev/window", "w" );
  650. dirp = opendir( dirname );
  651. mlen = strlen( mask );
  652. while ( ( dir = readdir( dirp ) ) != NULL ) {
  653.     if ( ( dir->d_name[0] != '.' ) && ( !strncmp( dir->d_name, mask, mlen ) ) ){
  654.         fprintf( wp, "\n%s%s", dirname, dir->d_name );
  655.         }
  656.     }
  657. closedir( dirp );
  658. fprintf( wp, "\n" );
  659. fflush( wp );
  660. sleep( WHOSLEEP );
  661. fclose( wp );
  662. signal( SIGALRM, SIG_IGN );
  663. }
  664.  
  665. showfsys()
  666.  
  667. /*    Show the root file system statistics.  Read the superblock in and get
  668.     free blocks, total blocks, and free inodes from it.  Also display the
  669.     freespace as a percentage.    */
  670.  
  671. {
  672. int rp;
  673. struct filsys fs;
  674.  
  675. signal( SIGALRM, justgoon );
  676. rp = open( "/dev/rfp002", O_RDONLY );
  677. lseek( rp, 512, 0 );
  678. read( rp, &fs, sizeof( fs ) );
  679. close( rp );
  680. printf( "\nRoot: %ldK free %ldK total %d%% free %d inodes", fs.s_tfree,
  681.     fs.s_fsize, (int)(100.0*(float)(fs.s_tfree)/(float)(fs.s_fsize)),
  682.     fs.s_tinode );
  683. fflush( stdout );
  684. sleep( 5 );
  685. printf( "\n" );
  686. signal( SIGALRM, SIG_IGN );
  687. }
  688.  
  689. help()
  690.  
  691. /*    Print a help message on key usage.    */
  692.  
  693. {
  694. FILE    *wp;
  695.  
  696. signal( SIGALRM, justgoon );
  697. wp = fopen( "/dev/window", "w" );
  698. fprintf( wp, "\t- Phone line states\n\t\to Idle - completely free line\n" );
  699. fprintf( wp, "\t\to Ansr - computer answering line (getty job)\n" );
  700. fprintf( wp, "\t\to Mach - incoming machine\n\t\to User - incoming user\n" );
  701. fprintf( wp, "\t\to Call - any outbound\n\t- Boot date and time\n" );
  702. fprintf( wp, "\t- Current run level\n\t- Current date and time\n\t- Number of users\n" );
  703. fprintf( wp, "\tWhen Suspend is hit, it makes the next window current; Resume\n" );
  704. fprintf( wp, "\tmakes the last window current.\n\n" );
  705. fprintf( wp, "\tThe following functions are mapped to the function keys:\n" );
  706. fprintf( wp, "\tShift-F1:  process display, similar to 'ps -ef'\n" );
  707. fprintf( wp, "\tShift-F2:  utmp display, like 'who'\n" );
  708. fprintf( wp, "\tShift-F3:  lists UUCP LCK.. files, if any\n" );
  709. fprintf( wp, "\tShift-F4:  directory of /usr/mail\n" );
  710. fprintf( wp, "\tShift-F5:  Root filesystem freespace and free inodes\n" );
  711. fprintf( wp, "\tShift-F6:  lists UUCP C. files, if any\n" );
  712. fprintf( wp, "\tShift-F7:  lists UUCP X. files, if any\n" );
  713. fprintf( wp, "\tShift-F8:  directory of /usr/spool/uucp\n" );
  714. fprintf( wp, "\tShift-Print:  display this list" );
  715. fflush( wp );
  716. sleep( WHOSLEEP );
  717. fclose( wp );
  718. signal( SIGALRM, SIG_IGN );
  719. }
  720.  
  721. dmemcopy( devmem, buf, memloc, nbytes )
  722. int    devmem;
  723. char    *buf;
  724. long    memloc, nbytes;
  725.  
  726. /*    Read from a memory device into a local buffer.    */
  727.  
  728. {
  729. lseek( devmem, memloc, 0 );
  730. read( devmem, buf, (unsigned)nbytes ); 
  731. }
  732.  
  733. printproc( wp, kmem, mem, ppt )
  734. FILE    *wp;
  735. int    kmem, mem;
  736. struct proc    *ppt;
  737.  
  738. /*    Get a process table entry and print some of the information from it.    */
  739.  
  740. {
  741. struct proc p;
  742. struct user    u;
  743. struct passwd    *pwd, *getpwuid();
  744. char    curtime[26], ptty[7], *getptty();
  745.  
  746. dmemcopy( kmem, (char *)&p, (long)ppt, (long)sizeof( struct proc ) );
  747. if ( p.p_flag & SLOAD ) {
  748.     dmemcopy( mem, (char *)&u, (long)( ctob( p.p_addr[0] )+U_OFFSET ),
  749.         (long)sizeof( struct user ) );
  750.     pwd = getpwuid( p.p_uid );
  751.     fprintf( wp, "%8s ", pwd->pw_name );
  752.     pwd = getpwuid( p.p_suid );
  753.     fprintf( wp, "%8s %5d %5d ", pwd->pw_name, p.p_pid, p.p_ppid );
  754.     strcpy( curtime, fmttime( localtime( &u.u_start ) ) );
  755.     strcpy( ptty, getptty( u.u_ttyd ) );
  756.     fprintf( wp, "%11s %6s %s\n", curtime, ptty, u.u_comm );
  757.     fflush( wp );
  758.     }
  759. }
  760.  
  761. char    *getptty( devno )
  762. dev_t    devno;
  763.  
  764. /*    Go from a device number to a device name.    */
  765.  
  766. {
  767. DIR    *dirp;
  768. struct directy    *dir;
  769. struct stat    sbuf;
  770. char    name[14];
  771. static char    tname[7];
  772.  
  773. strcpy( tname, "none" );
  774. if ( !devno )
  775.     return( tname );
  776. dirp = opendir( DEVDIR );
  777. while ( ( dir = readdir( dirp ) ) != NULL ) {
  778.     if ( dir->d_name[0] != '.' ) {
  779.         strcpy( name, DEVDIR );
  780.         strcat( name, dir->d_name );
  781.         stat( name, &sbuf );
  782.         if ( devno == sbuf.st_rdev ) {
  783.             closedir( dirp );
  784.             strcpy( tname, dir->d_name );
  785.             return( tname );
  786.             }
  787.         }
  788.     }
  789. closedir( dirp );
  790. return( tname );
  791. }
  792.  
  793. showutent( fp, u )
  794. FILE    *fp;
  795. struct    utmp *u;
  796.  
  797. /*    Print a formatted utmp entry.    */
  798.  
  799. {
  800. char    curtime[26], *fmttime();
  801.  
  802. strcpy( curtime, fmttime( localtime( &( u->ut_time ) ) ) );
  803. fprintf( fp, "%8s %14s %11s %5d\n", u->ut_user, u->ut_line, curtime, u->ut_pid );
  804. }
  805.  
  806. SHAR_EOF
  807. fi # end of overwriting check
  808. if test -f 'startmgr.c'
  809. then
  810.        echo shar: will not over-write existing file "'startmgr.c'"
  811. else
  812. cat << \SHAR_EOF > 'startmgr.c'
  813. /*    startmgr:  Create a one-line window on the top line of the Unix-PC
  814.     (7300/3B1) screen and start a program running in that window.
  815.     Declare this window to be the Window Manager, which gives it control
  816.     over the Suspend, Resume and Print keys.  This is meant to be used to
  817.     start newmgr, but can probably be adapted to be a fairly generic program
  818.     starter.  It was designed to mimic the observed operation of things like
  819.     cron, smgr, etc.
  820.  
  821.     This software is Copyright (c) 1987 by Scott Hazen Mueller.
  822.  
  823.     Permission is hereby granted to copy, reproduce, redistribute or
  824.     otherwise use this software as long as: there is no monetary
  825.     profit gained specifically from the use or reproduction or this
  826.     software, it is not sold, rented, traded or otherwise marketed, and
  827.     this copyright notice is included prominently in any copy
  828.     made.
  829.  
  830.     The author make no claims as to the fitness or correctness of
  831.     this software for any use whatsoever, and it is provided as is. 
  832.     Any use of this software is at the user's own risk.
  833.  
  834.     (Copyright notice courtesy of News 2.11 :-)
  835.  
  836.     Additionally:  you break it, you bought it.  I've listed the problems
  837.     that I know of in comments in the code; if you come up with fixes, I'd
  838.     like to see them, but I'm not planning on supporting anything.  It's
  839.     "good enough"; that's all that I'm looking for.    */
  840.  
  841. #include    <stdio.h>
  842. #include    <sys/types.h>
  843. #include    <wind.h>
  844. #include    <sys/window.h>
  845. #include    <fcntl.h>
  846. #include    <termio.h>
  847.  
  848. /*    Parameters defining the window and the program for that window.  You'll
  849.     almost certainly have to change barprog to correspond with whatever
  850.     directory you use for your local stuff.
  851.  
  852.     Note:  WFLAGS was determined empirically, by looking at the flags for
  853.     the AT&T-supplied smgr window.  No guarantees here.    */
  854.  
  855. #define        BARPROG        "/usr/local/newmgr"
  856. #define        WXSTART        0
  857. #define        WYSTART        0
  858. #define        WWIDTH        720
  859. #define        WHEIGHT        12
  860. #define        WFLAGS        257
  861.  
  862. main()
  863. {
  864. int    wd, dummy;
  865. struct uwdata winbar;
  866. struct utdata winname;
  867. struct termio bartty;
  868.  
  869. winbar.uw_x = WXSTART;
  870. winbar.uw_y = WYSTART;
  871. winbar.uw_width = WWIDTH;
  872. winbar.uw_height = WHEIGHT;
  873. winbar.uw_uflags = WFLAGS;
  874. winname.ut_num = WTXTUSER;
  875.  
  876. strcpy( winname.ut_text, "Invisible" );
  877. if ( fork() )
  878.     exit( 0 );
  879. else {
  880.  
  881. /*    Setpgrp() cannot be called from processes associated with windows.
  882.     From the manual.  Since it's a cleaner model for the parent to redirect
  883.     the child's stdin, stdout and stderr, we do that.  We have to setpgrp(),
  884.     or else the child would be killed when the process group leader exited.    */
  885.  
  886.     fclose( stdin );
  887.     fclose( stdout );
  888.     fclose( stderr );
  889.     setpgrp();
  890.  
  891. /*    Get a window, and set it up according to our parameters.  Since stdin
  892.     was closed above, wd gets to be stdin (roughly).    */
  893.  
  894.     wd = open( "/dev/window", O_RDWR|O_EXCL, 0 );
  895.     ioctl( wd, WIOCSETD, &winbar );
  896.     ioctl( wd, WIOCSETTEXT, &winname );
  897.     ioctl( wd, WIOCSYS, SYSWMGR );
  898.     ioctl( wd, WIOCSYS, SYSPMGR );
  899.  
  900. /*    Set up the child's stdout and stderr to point at the window.    */
  901.  
  902.     dup( wd );
  903.     dup( wd );
  904.  
  905. /*    Set terminal parameters; after all, we'll want to read escape codes and
  906.     other neat stuff.    */
  907.  
  908.     ioctl( wd, TCGETA, &bartty );
  909.     bartty.c_iflag &= ~IGNBRK;
  910.     bartty.c_lflag &= ~( ICANON | ECHO );
  911.  
  912. /*    Read three characters at a time; 1 second timeout interval.  Whether
  913.     this really does anything, I don't know.    */
  914.  
  915.     bartty.c_cc[4] = 3;
  916.     bartty.c_cc[5] = 10;
  917.     ioctl( wd, TCSETA, &bartty );
  918.     
  919. /*    Execute with no command line arguments.    */
  920.  
  921.     execl( BARPROG, BARPROG, 0 );
  922.     }
  923. }
  924.  
  925. SHAR_EOF
  926. fi # end of overwriting check
  927. if test -f 'ndir.c'
  928. then
  929.        echo shar: will not over-write existing file "'ndir.c'"
  930. else
  931. cat << \SHAR_EOF > 'ndir.c'
  932. #if !defined(BSD4_2) && !defined(BSD4_1C) && !defined(HP9K5)
  933. #ifdef M_XENIX
  934. #include <sys/types.h>
  935. #endif /* M_XENIX */
  936. #include <sys/param.h>
  937. #include "ndir.h"
  938.  
  939. #ifdef SCCSID
  940. static char    *SccsId = "@(#)ndir.c    1.12    10/15/87";
  941. #endif /* SCCSID */
  942.  
  943. /*
  944.  * support for Berkeley directory reading routine on a V7 file system
  945.  */
  946.  
  947. extern char *malloc();
  948.  
  949. /*
  950.  * open a directory.
  951.  */
  952. DIR *
  953. opendir(name)
  954. char *name;
  955. {
  956.     register DIR *dirp;
  957.     register int fd;
  958.  
  959.     if ((fd = open(name, 0)) == -1)
  960.         return NULL;
  961.     if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
  962.         close (fd);
  963.         return NULL;
  964.     }
  965.     dirp->dd_fd = fd;
  966.     dirp->dd_loc = 0;
  967.     return dirp;
  968. }
  969.  
  970. /*
  971.  * read an old style directory entry and present it as a new one
  972.  */
  973. #ifdef pyr
  974. /* Pyramid in the AT&T universe */
  975. #define ODIRSIZ 248
  976. struct olddirect {
  977.     long    od_ino;
  978.     short    od_fill1, od_fill2;
  979.     char od_name[ODIRSIZ];
  980. };
  981. #else /* V7 file system */
  982. #define    ODIRSIZ    14
  983.  
  984. struct    olddirect {
  985.     short    od_ino;
  986.     char    od_name[ODIRSIZ];
  987. };
  988. #endif /* !pyr */
  989.  
  990. /*
  991.  * get next entry in a directory.
  992.  */
  993. struct directy *
  994. readdir(dirp)
  995. register DIR *dirp;
  996. {
  997.     register struct olddirect *dp;
  998.     static struct directy dir;
  999.  
  1000.     for (;;) {
  1001.         if (dirp->dd_loc == 0) {
  1002.             dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 
  1003.                 DIRBLKSIZ);
  1004.             if (dirp->dd_size <= 0)
  1005.                 return NULL;
  1006.         }
  1007.         if (dirp->dd_loc >= dirp->dd_size) {
  1008.             dirp->dd_loc = 0;
  1009.             continue;
  1010.         }
  1011.         dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
  1012.         dirp->dd_loc += sizeof(struct olddirect);
  1013.         if (dp->od_ino == 0)
  1014.             continue;
  1015.         dir.d_ino = dp->od_ino;
  1016.         strncpy(dir.d_name, dp->od_name, ODIRSIZ);
  1017.         dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
  1018.         dir.d_namlen = strlen(dir.d_name);
  1019.         dir.d_reclen = DIRSIZ(&dir);
  1020.         return (&dir);
  1021.     }
  1022. }
  1023.  
  1024. /*
  1025.  * close a directory.
  1026.  */
  1027. void
  1028. closedir(dirp)
  1029. register DIR *dirp;
  1030. {
  1031.     close(dirp->dd_fd);
  1032.     dirp->dd_fd = -1;
  1033.     dirp->dd_loc = 0;
  1034.     free((char *)dirp);
  1035. }
  1036.  
  1037. /*
  1038.  * seek to an entry in a directory.
  1039.  * Only values returned by "telldir" should be passed to seekdir.
  1040.  */
  1041. void
  1042. seekdir(dirp, loc)
  1043. register DIR *dirp;
  1044. long loc;
  1045. {
  1046.     long curloc, base, offset;
  1047.     struct directy *dp;
  1048.     long lseek(), telldir();
  1049.  
  1050.     curloc = telldir(dirp);
  1051.     if (loc == curloc)
  1052.         return;
  1053.     base = loc & ~(DIRBLKSIZ - 1);
  1054.     offset = loc & (DIRBLKSIZ - 1);
  1055.     (void) lseek(dirp->dd_fd, base, 0);
  1056.     dirp->dd_loc = 0;
  1057.     while (dirp->dd_loc < offset) {
  1058.         dp = readdir(dirp);
  1059.         if (dp == NULL)
  1060.             return;
  1061.     }
  1062. }
  1063.  
  1064. /*
  1065.  * return a pointer into a directory
  1066.  */
  1067. long
  1068. telldir(dirp)
  1069. DIR *dirp;
  1070. {
  1071.     return lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc;
  1072. }
  1073. #endif /* !BSD4_2 && !BSD4_1C && !HP9K5 */
  1074. SHAR_EOF
  1075. fi # end of overwriting check
  1076. if test -f 'ndir.h'
  1077. then
  1078.        echo shar: will not over-write existing file "'ndir.h'"
  1079. else
  1080. cat << \SHAR_EOF > 'ndir.h'
  1081. /*    @(#)ndir.h    1.7    10/7/87    */
  1082. #if defined(HP9K5)
  1083. /* He should have included it instead of this, but prevent confusion */
  1084. #include <ndir.h>
  1085. #else /* other */
  1086. #ifndef DEV_BSIZE
  1087. #define    DEV_BSIZE    512
  1088. #endif
  1089. #define DIRBLKSIZ    DEV_BSIZE
  1090. #define    MAXNAMLEN    255
  1091.  
  1092. struct    directy {
  1093.     long    d_ino;            /* inode number of entry */
  1094.     short    d_reclen;        /* length of this record */
  1095.     short    d_namlen;        /* length of string in d_name */
  1096.     char    d_name[MAXNAMLEN + 1];    /* name must be no longer than this */
  1097. };
  1098.  
  1099. /*
  1100.  * The DIRSIZ macro gives the minimum record length which will hold
  1101.  * the directory entry.  This requires the amount of space in struct directy
  1102.  * without the d_name field, plus enough space for the name with a terminating
  1103.  * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
  1104.  */
  1105.  
  1106. #ifdef DIRSIZ
  1107. #undef DIRSIZ
  1108. #endif /* DIRSIZ */
  1109. #define DIRSIZ(dp) \
  1110.     ((sizeof (struct directy) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
  1111.  
  1112. /*
  1113.  * Definitions for library routines operating on directories.
  1114.  */
  1115. typedef struct _dirdesc {
  1116.     int    dd_fd;
  1117.     long    dd_loc;
  1118.     long    dd_size;
  1119.     char    dd_buf[DIRBLKSIZ];
  1120. } DIR;
  1121. #ifndef NULL
  1122. #define NULL 0
  1123. #endif
  1124. extern    DIR *opendir();
  1125. extern    struct directy *readdir();
  1126. extern    void closedir();
  1127.  
  1128. #define rewinddir(dirp)    seekdir((dirp), (long)0)
  1129. #endif /* other */
  1130. SHAR_EOF
  1131. fi # end of overwriting check
  1132. #    End of shell archive
  1133. exit 0
  1134. -- 
  1135. Scott Hazen Mueller   uunet!zorch!scott   scott@zorch.UU.NET
  1136. (408) 245-9461
  1137.